package com.uflower.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.uflower.common.to.UserLoginTo;
import com.uflower.common.utils.R;
import com.uflower.order.feign.ProductFeignService;
import com.uflower.order.interceptor.LoginUserInterceptor;
import com.uflower.order.service.CartService;
import com.uflower.order.to.SkuFullReductionTo;
import com.uflower.order.to.SkuInfoTo;
import com.uflower.order.vo.CartItemVo;
import com.uflower.order.vo.CartVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service("cartService")
public class CartServiceImpl implements CartService {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    ProductFeignService productFeignService;

    @Autowired
    private ThreadPoolExecutor executor;

    private final String CART_PREFIX = "uflower:cart:";

    @Override
    public CartItemVo addCartItem(Long skuId, Integer num) throws ExecutionException, InterruptedException {

        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        //封装购物项
        CartItemVo cartItemVo;
        Object o = cartOps.get(skuId.toString());
        //购物车中无该购物项
        if(o == null){
            cartItemVo = new CartItemVo();
            /******************************************/

            RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
            /********************************************/
            CompletableFuture<Void> getSkuInfo = CompletableFuture.runAsync(()->{

                RequestContextHolder.setRequestAttributes(requestAttributes);

                R r = productFeignService.getSkuInfo(skuId);
                SkuInfoTo sku = r.getData(new TypeReference<SkuInfoTo>() {
                }, "skuInfo");
                if(sku != null){
                    cartItemVo.setSkuId(sku.getSkuId());
                    cartItemVo.setTitle(sku.getSkuTitle());
                    cartItemVo.setImage(sku.getSkuDefaultImg());
                    cartItemVo.setCheck(true);
                    cartItemVo.setPrice(sku.getPrice());
                    cartItemVo.setCount(num);
                }
            },executor);
            //远程查询sku的组合shu
            CompletableFuture<Void> getSaleAttrValues = CompletableFuture.runAsync(()->{

                RequestContextHolder.setRequestAttributes(requestAttributes);

                List<String> saleAttrValues = productFeignService.getSkuSaleAttrValues(skuId);
                cartItemVo.setSkuAttrValues(saleAttrValues);
            },executor);

            //远程查询sku的满减信息
            CompletableFuture<Void> getSkuReduction = CompletableFuture.runAsync(() -> {

                RequestContextHolder.setRequestAttributes(requestAttributes);

                SkuFullReductionTo skuFullReductionTo = productFeignService.getSkuFullReduction(skuId);
                if(skuFullReductionTo != null){
                    cartItemVo.setFullReduce(new CartItemVo.FullReduce(skuFullReductionTo.getFullPrice(),
                            skuFullReductionTo.getReducePrice()));
                }
            }, executor);
            CompletableFuture.allOf(getSkuInfo,getSaleAttrValues,getSkuReduction).get();
        }else{
            String s = (String)o;
            cartItemVo = JSON.parseObject(s,CartItemVo.class);
            Integer count = cartItemVo.getCount();
            if (count != null){
                count += num;
                cartItemVo.setCount(count);
            }
        }

        String cartItem = JSON.toJSONString(cartItemVo);
        cartOps.put(skuId.toString(),cartItem);
        return cartItemVo;
    }

    @Override
    public void checkItem(Long skuId, Integer checked) {
        CartItemVo cartItem = getCartItem(skuId);

        if(cartItem == null) return;

        if (cartItem.getCheck() == (checked == 1)){
            return;
        }else{
            BoundHashOperations<String, Object, Object> cartOps = getCartOps();
            cartItem.setCheck(checked == 1);
            cartOps.put(skuId.toString(),JSON.toJSONString(cartItem));
        }
    }

    @Override
    public void updateItemCount(Long skuId, Integer num) {
        CartItemVo cartItem = getCartItem(skuId);


        if (cartItem == null|| cartItem.getCount().equals(num)) {
        }
        else{
            BoundHashOperations<String, Object, Object> cartOps = getCartOps();
            cartItem.setCount(num);
            cartOps.put(skuId.toString(),JSON.toJSONString(cartItem));
        }
    }

    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        cartOps.delete(skuId.toString());
    }

    @Override
    public List<CartItemVo> getCheckedItems(Long id) {
        String cartKey = CART_PREFIX+id;
        BoundHashOperations<String, Object, Object> cartOps = redisTemplate.boundHashOps(cartKey);
        List<Object> values = cartOps.values();
        List<CartItemVo> checkedItems = values.stream().map(v -> {
            return JSON.parseObject((String) v, CartItemVo.class);
        }).filter(items -> items.getCheck()).map(item -> {
            BigDecimal price = productFeignService.getPrice(item.getSkuId());
            item.setPrice(price);
            return item;
        }).collect(Collectors.toList());

        return checkedItems;
    }

    @Override
    public CartVo getCart() {
        CartVo cartVo = new CartVo();
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        Map<Object, Object> entries = cartOps.entries();
        List<CartItemVo> items = entries.values().stream().map(item -> {
            return JSON.parseObject((String) item, CartItemVo.class);
        }).collect(Collectors.toList());

        cartVo.setItems(items);
        cartVo.init();
        return cartVo;
    }

    //获取购物项
    @Override
    public CartItemVo getCartItem(Long skuId){
        BoundHashOperations<String, Object, Object> cartOps = getCartOps();
        CartItemVo cartItemVo;
        Object o = cartOps.get(skuId.toString());
        if(o != null){
            String s = (String)o;
            return JSON.parseObject(s,CartItemVo.class);
        }else{
            return null;
        }
    }
    //绑定hash的键
    private BoundHashOperations<String, Object, Object> getCartOps() {
        UserLoginTo loginUser= LoginUserInterceptor.loginUser.get();
        String cartKey = "";

        //默认用户已登录
        cartKey = CART_PREFIX + loginUser.getId();
        BoundHashOperations<String, Object, Object> operations = redisTemplate.boundHashOps(cartKey);
        return operations;
    }
}
